#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <cctype>
#include <stdexcept>
#include "SDL.h"
#include "SDL_image.h"
#include "location.h"
#include "character.h"
#include "tree.h"
#include "CLI.h"
#include "item.h"
#include "mapitem.h"
#include "itemfactory.h"
#include "mapitemfactory.h"
#include "astar.h"
#include "node.h"

using namespace std;

int CLI::run()
{	  
   Tree map_tree;
   bool exit_flag = false;
   string command, c2, line;
   Location* now = 0, *temp_l = 0;
   Character me("PC", "BlackRanger", 0,0);
   char menu = 'n';
   while(menu != 'g' && menu != 'd')
   {
	  cout << "Press G for game mode or D for designer mode:  ";
	  cin.get(menu);
	  menu = tolower(menu);
   }

//    menu = 'd';
   getline(cin,line);
   cout <<  endl;
   
   while(exit_flag == false)
   {
	  getline(cin, line);
	  istringstream is(line);
	  is >> command;

	  if(command == "quit")
		 exit_flag = true;

	  else if(command == "look")
	  {
		 description(now, map_tree);
	  }
	  else if(command == "go")
	  {
		  string restr;
		  is >> command;
		  if((temp_l = map_tree.find_exit(now, command)) != 0)
		  {
			  restr = temp_l->findRestrictions(me);
			  if(restr == "")
				  now = temp_l;
			  else
				  cout << "You need " << restr << " to enter " << command << endl;
		  }
		  else
		  {
			  cout << "\nI don't know how to get there.\n\n";
		  }
	  }
	  else if(command == "take")
	  {
		  is >> command;
		  Item* takeItem = now->getItem(command);
		  if(takeItem != 0)
		  {
			  me.add(takeItem);
			  now->removeItem(takeItem);
		  }
		  else
			  cout << "\nThere is no " << command << " here.\n\n";
	  }
	  else if(command == "drop")
	  {
		  is >> command;
		  if(me.find(command))
		  {
			  Item* removeItem = me.getItem(command);
			  me.remove(removeItem);
			  now->addItem(removeItem);
		  }
		  else
			  cout << "\nYou don't have any " << command << ".\n\n";
	  }
	  else if(command == "inventory")
	  {  
		  cout << "You have: " << me.items() << endl;
	  }
	  else if(command == "load")
	  {
		 is >> command;
		 now = map_tree.load(command);
		 // cout << command << " loaded.\n";
	  }
	  
	  //spelskapar-kommandon:
	  else if(menu == 'd')
	  {
		 if(command == "location")
		 {
			is >> command;
			location(command, map_tree);
			//cout << "location " << command << " added\n";
		 }
		 else if(command == "delete") // ta bort location
		 {
			is >> command;
			if((temp_l = map_tree.find_l(command)) != 0)
			   map_tree.remove(command);
			else
			   cout << "There is no such location.\n";
		 }
		 else if(command == "exit")
		 {
			is >> command;
			if((temp_l = map_tree.find_l(command)) != 0)
			{
			   is >> command;
			   temp_l->addLocation(command);
			}
			else
			   cout << "location does not exist\n";
		 }
		 // example: "add garden sword" create an item type sword in garden
		 else if(command == "add")
		 {
			 is >> command;
			 if((temp_l = map_tree.find_l(command)) != 0)
			 {
				 ItemFactory* itemfactory = new ItemFactory();
				 
				 is >> command;
				 Item* itemToAdd = itemfactory->build(command);
				 temp_l->addItem(itemToAdd);		 
			 }
			 else
				 cout << "location does not exist\n";
		 }
		 else if(command == "remove") //ta bort item fran en location.
		 {
			 is >> command;
			 if((temp_l = map_tree.find_l(command)) != 0)
			 {
				 is >> command;
				 temp_l->removeItem(temp_l->getItem(command));
			 }
			 else
			 {
				 cout << "location does not exist\n";
			 }
		 }
		 else if(command == "restriction")
		 {
			is >> command;
			if((temp_l = map_tree.find_l(command)) !=0)
			{
			   is >> command;
			   temp_l->addRestriction(command);
			}
			else
			   cout << "location does not exist\n";
		 }
		 else if(command == "release")
		 {
			 is >> command;
			 if((temp_l = map_tree.find_l(command)) != 0)
			 {
				 is >> command;
				 temp_l->removeRestriction(command);
			 }
			 else
				 cout << "location does not exist\n";
		 }
		 else if(command == "description")
		 {
			is >> command;
			if((temp_l = map_tree.find_l(command)) !=0)
			{
			   cout << "Enter new description for "
					<< temp_l->getName() <<":\n";
			   getline(cin, command);
			   temp_l->setDescription(command);
			}
			else
			   cout << "location does not exist\n";
		 }		   
		 else if(command == "describe")
		 {
			is >> command;
			if((temp_l = map_tree.find_l(command)) != 0)
			   description(temp_l, map_tree);
			else
			   cout << "Location does not exist\n";
		 }
		 else if(command == "jump")
		 {
			is >> command;
			if((temp_l = map_tree.find_l(command)) != 0)
			   now = temp_l;
			else
			   cout << "No such location\n";
		 }
		 else if(command == "help")
			design_help();
		 else if(command == "save")
		 {
			is >> command;
			map_tree.save(command);
			cout << "Map " << command << " is saved.\n";
		 }
		 else if(command == "print")
		 {
			map_tree.print_tree();
		 }
		 else if(command == "tile"){
			 MapItemFactory* mapitemfactory = new MapItemFactory();
			 string mapItem = "";
			 string locationName = "";
			 string xread = "";
			 string yread = "";
			 int x = 0;
			 int y = 0;
			 
			 // Get the id for the mapItem we want to add
			 cout << "Enter id: " << endl;
			 getline(cin, mapItem);
			 
			 // Get the name of the lcation we want to add it to
			 cout << "Enter location name: " << endl;
			 getline(cin, locationName);
			 
			 // Get the x koordinate
			 cout << "Enter the x koordinate: " << endl;
			 getline(cin, xread);
			 istringstream xis;
			 xis.str(xread);
			 xis >> x;
			 
			 // Get the y koordinate
			 cout << "Enter the y koordinate: " << endl;
			 getline(cin, yread);
			 istringstream yis;
			 yis.str(yread);
			 yis >> y;
			 
			 // Check if the location exists
			 if((temp_l = map_tree.find_l(locationName)) != 0)
			 {
				 MapItem* mapItemToAdd = mapitemfactory->build(mapItem);
				 if(mapItemToAdd != 0)
					 temp_l->map_[x][y] = mapItemToAdd;
			 }
			 else
				 cout << "location does not exist\n";
		 }
		 else if(command == "tileall"){
			 MapItemFactory* mapitemfactory = new MapItemFactory();
			string mapItem = "";
			string locationName = "";

			// Get the id for the mapItem we want to add
			cout << "Enter id: " << endl;
			getline(cin, mapItem);
			
			// Get the name of the lcation we want to add it to
			cout << "Enter location name: " << endl;
			getline(cin, locationName);
			
			// Check if the location exists
			if((temp_l = map_tree.find_l(locationName)) != 0)
			{			 			   
				for(int y = 0; y < 44; y++)
				{
					for(int x = 0; x < 17; x++)
					{
						MapItem* mapItemToAdd = mapitemfactory->build(mapItem);
						if(mapItemToAdd != 0)
							temp_l->map_[x][y] = mapItemToAdd;
						
					}
				}			   				  
			}
			
			else
				cout << "location does not exist\n";
			
		 }
		 else if(command == "create")
		 {
			 string id = "";
			 string name = "";
			 string desc = "";
			 string picname = "";
			 string kind = "";
			 
			 cout << "What kind of item do you want to create?" << endl;
			 cout << "Choose: item, mapitem" << endl;
			 getline(cin, kind);

			 if(kind == "item")
			 {
				 ItemFactory *itemfactory = new ItemFactory();
				 
				 cout << "Enter id: " << endl;
				 getline(cin, id);
				 itemfactory->create(id);
				 
				 cout << "Enter name: " << endl;
				 getline(cin, name);
				 itemfactory->setName(name);
				 
				 cout << "Enter description: " << endl;
				 getline(cin, desc);
				 itemfactory->setDescription(desc);
				 
				 cout << "Enter picpath: " << endl;
				 getline(cin, picname);
				 itemfactory->setPicName(picname);
				 
				 itemfactory->save();
			 }
			 else if(kind == "mapitem")
			 {
				 string walkable = "";
				 MapItemFactory *itemfactory = new MapItemFactory();
				 
				 cout << "Enter id: " << endl;
				 getline(cin, id);
				 itemfactory->create(id);
				 
				 cout << "Enter name: " << endl;
				 getline(cin, name);
				 itemfactory->setName(name);
				 
				 cout << "Enter description: " << endl;
				 getline(cin, desc);
				 itemfactory->setDescription(desc);
				 
				 cout << "Enter picpath: " << endl;
				 getline(cin, picname);
				 itemfactory->setPicName(picname);

				 cout << "Is the mapitem walkable? (true,false): " << endl;
				 getline(cin, walkable);
				 if(walkable == "true")
				 {
					 itemfactory->setWalkable(true);
				 }
				 else if(walkable == "false")
				 {
					 itemfactory->setWalkable(false);
				 }
				 else
				 {					 
					 cout << "Not a valid option, setting to true" << endl;
					 itemfactory->setWalkable(true);
				 }
				 itemfactory->setPortal(false);
				 itemfactory->setItem(false);
				 itemfactory->save();
			 }
			 else
			 {
				 cout << "That item type does not exist!" << endl;
			 }
			 
				 			 
		 }
		 else if(command == "edit")
		 {
			 bool done = false;
			 string choice;
			 string id = "";
			 string name = "";
			 string desc = "";
			 string picname = "";
			 string kind = "";
			 
			 cout << "Which item type to edit?" << endl;
			 cout << "Choose: item, mapitem" << endl;
			 getline(cin, kind);
			 
			 if(kind == "item")
			 {
				 ItemFactory* itemfactory = new ItemFactory();
				 cout << "Choose blueprint to edit (write the id)" << endl;
				 getline(cin, id);
				 itemfactory->load(id);
				 
				 cout << "Choose id,name,desc,picname to change that setting." << endl;
				 cout << "Write delete to remove the blueprint." << endl;
				 cout << "Write done when finished!" << endl;
				 while(done == false)
				 {
					 getline(cin, choice);
					 
					 if(choice == "id")
					 {
						 cout << "Choose the new id" << endl;
						 getline(cin, id);
						 itemfactory->setId(id);
						 id = "";
					 }
					 else if(choice == "name")
					 {
						 cout << "Choose the new name" << endl;
						 getline(cin, name);
						 itemfactory->setName(name);
						 name = "";
					 }
					 else if(choice == "desc")
					 {
						 cout << "Choose the new description" << endl;
						 getline(cin, desc);
						 itemfactory->setDescription(desc);
						 desc = "";
					 }
					 else if(choice == "picname")
					 {
						 cout << "Choose the new picname" << endl;
						 getline(cin, picname);
						 itemfactory->setPicName(picname);
						 picname = "";
					 }
					 else if(choice == "delete")
					 {
						 itemfactory->delItem();
						 done = true;
					 }
					 else if(choice == "done")
					 {
						 done = true;
						 itemfactory->save();
					 }
					 else
					 {
						 cout << "Invalid command! Choose id,name,desc or picname to change it. Write done when finished!" << endl;
					 }
					 
					 choice = ""; 
				 }
			 }
			 else if(kind == "mapitem")
			 {
				 string walkable = "";
				 MapItemFactory* itemfactory = new MapItemFactory();
				 cout << "Choose blueprint to edit (write the id)" << endl;
				 getline(cin, id);
				 itemfactory->load(id);
				 
				 cout << "Choose id,name,desc,picname,walkable to change that setting." << endl;
				 cout << "Write delete to remove the blueprint." << endl;
				 cout << "Write done when finished!" << endl;
				 while(done == false)
				 {
					 getline(cin, choice);
					 
					 if(choice == "id")
					 {
						 cout << "Choose the new id" << endl;
						 getline(cin, id);
						 itemfactory->setId(id);
						 id = "";
					 }
					 else if(choice == "name")
					 {
						 cout << "Choose the new name" << endl;
						 getline(cin, name);
						 itemfactory->setName(name);
						 name = "";
					 }
					 else if(choice == "desc")
					 {
						 cout << "Choose the new description" << endl;
						 getline(cin, desc);
						 itemfactory->setDescription(desc);
						 desc = "";
					 }
					 else if(choice == "picname")
					 {
						 cout << "Choose the new picname" << endl;
						 getline(cin, picname);
						 itemfactory->setPicName(picname);
						 picname = "";
					 }
					 else if(choice == "delete")
					 {
						 itemfactory->delItem();
						 done = true;
					 }
					 else if(choice == "done")
					 {
						 done = true;
						 itemfactory->save();
					 }
					 else if(choice == "walkable")
					 {
						 cout << "Is the mapitem walkable? (true,false): " << endl;
						 getline(cin, walkable);
						 if(walkable == "true")
						 {
							 itemfactory->setWalkable(true);
						 }
						 else if(walkable == "false")
						 {
							 itemfactory->setWalkable(false);
						 }
						 else
						 {					 
							 cout << "Not a valid option, setting to true" << endl;
							 itemfactory->setWalkable(true);
						 }
					 }
					 else
					 {
						 cout << "Invalid command! Choose id,name,desc or picname to change it. Write done when finished!" << endl;
					 }
					 
					 choice = ""; 
				 }
			 }
			 else
			 {
				 cout << "That item type does not exist!" << endl;
			 }
			 
		 }
		 else if(command == "info")
		 {
			 string kind = "";
			 string id = "";
			 
			 cout << "Which item type do you want to load and get info about?" << endl;
			 cout << "Choose: item, mapitem" << endl;
			 
			 getline(cin, kind);
			 
			 if(kind == "item")
			 {
				 Item* item = new Item();
				 ItemFactory* factory = new ItemFactory();
				 cout << "Enter the id of the item to get info about" << endl;
				 getline(cin, id);
				 
				 item = factory->build(id);
				 cout << "id: " << item->getId() << endl;
				 cout << "name: " << item->getName() << endl;
				 cout << "picname: " << item->getPicName() << endl;
				 cout << "desc: " << item->getDescription() << endl;
				 cout << "x: " << item->getX() << endl;
				 cout << "y: " << item->getY() << endl;
			 }
			 else if (kind == "mapitem")
			 {
				 MapItem* item = new MapItem();
				 MapItemFactory* factory = new MapItemFactory();
				 cout << "Enter the id of the item to get info about" << endl;
				 getline(cin, id);
				 
				 item = factory->build(id);
				 cout << "id: " << item->getId() << endl;
				 cout << "name: " << item->getName() << endl;
				 cout << "picname: " << item->getPicName() << endl;
				 cout << "desc: " << item->getDescription() << endl;
				 cout << "x: " << item->getX() << endl;
				 cout << "y: " << item->getY() << endl;
				 cout << "walkable: " << item->getWalkable() << endl;
			 }
			 else
			 {
				 cout << "That item type does not exist!" << endl; 
				 getline(cin, id);
			 }
			 
		 }
		 else if(command == "findway"){
			 string fromx = "";
			 string fromy = "";
			 string tox = "";
			 string toy = "";
			 int fromx_ = 0;
			 int fromy_ = 0;
			 int tox_ = 0;
			 int toy_ = 0;
			 string loc = "";
			 vector<Node*> foundway;
			 cout << "Enter which location you want to move in: " << endl;
			 getline(cin, loc);
			 
			 temp_l = map_tree.find_l(loc);
			 
			 if(temp_l != 0)
			 {
				 cout << "Enter the koordinates to move FROM: " << endl;
				 cout << "X: ";
				 getline(cin, fromx);
				 cout << endl;
				 cout << "Y: ";
				 getline(cin, fromy);
				 cout << endl;
				 cout << "Enter the koordinates to move TO: " << endl;
				 cout << "X: ";
				 getline(cin, tox);
				 cout << endl;
				 cout << "Y: ";
				 getline(cin, toy);

				 istringstream xfis;
				 xfis.str(fromx);
				 xfis >> fromx_;
				 
				 istringstream yfis;
				 yfis.str(fromy);
				 yfis >> fromy_;

				 istringstream xtis;
				 xtis.str(tox);
				 xtis >> tox_;

				 istringstream ytis;
				 ytis.str(toy);
				 ytis >> toy_;
				 
				 Astar* wayalg = new Astar(temp_l, fromx_, fromy_, tox_, toy_);
				 foundway = wayalg->getWay();

				 cout << endl;
				 cout << "We found this way: " << endl;

				 for(int i = 0; i < foundway.size() ; i++)
				 {
					 int xx = foundway[i]->getx();
					 int yy = foundway[i]->gety();
					 cout << xx << " ";
					 cout << yy << endl;
					 
				 }
				 
				 
			 }
			 else
			 {
				 cout << "That location does not exist!" << endl;
			 }
			 
		 }
		 else
			 cout << "Not a valid command.\n";
	  }
	  else if(command == "help")
		  cli_help();
	  
	  else
		  cout << "Not a valid command.\n";
	  
   }
   
   return 0;
}

/* funktion for att skapa nytt Location objekt. Namnet pa objektet anges
 * som argument.
 */
Location* CLI::location(string& name, Tree& map_tree)
{
   if(map_tree.find_l(name) != 0)
   {
	  cout << "Location already exists\n";
	  return 0;
   }
   else
   {
	  Location* new_location = new Location;
	  new_location->setName(name);
	  new_location->right_node = 0;
	  new_location->left_node = 0;
	  new_location->setDescription("");
	  map_tree.add(new_location);
	  return new_location;
   }
}

/* description skriver ut information om en plats */
void description(Location* l, Tree& map_tree)
{
   if(l != 0)
   {
	  string descr;
	  if((descr = l->getDescription()) == "")	  
		 cout << "You are currently at " << l->getName() << ".\n";
	  else
		 cout << descr << endl;
	  string items = l->getItems();
	  if(items != "")
	  {
		 cout << "Here is: " << items << ".\n";
	  }
   }   
}

void cli_help()
{
   cout << "Commands:\n" << "quit - exit game\n"
	    << "look - get description of current location\n"
	    << "go LOCATION - move to LOCATION\n"
	    << "take ITEM - pick up ITEM\n"
	    << "drop ITEM - drop TIEM\n"
	    << "inventory - get a list of your inventory\n"
	    << "load MAP - load MAP\n"
	    << "help - get a list of commands\n";
}

void design_help()
{
	cli_help();
	cout << "\nDesigner commands:\n"
	     << "location LOCATION - add LOCATION\n"
	     << "delete LOCATION - delete LOCATION\n"
	     << "exit LOCATION EXIT - add EXIT to LOCATION\n"
	     << "add LOCATION ITEM - add ITEM to LOCATION\n"
	     << "remove LOCATION ITEM - remove ITEM from LOCATION\n"
	     << "description LOCATION - write a new description for LOCATION\n"
	     << "describe LOCATION - get a description of LOCATION\n"
	     << "jump LOCATION - move to LOCATION\n"
	     << "print - print the location tree\n"
	     << "tile itemnumber location x y - Add a tile to the x,y coordinate in location\n"
	     << "tileall itemnumber location - Fill the whole location with the same tile\n"
	     << "findway - Use the Astar algorithm to find a way in the location\n"
	     << "save MAP - save current map\n";
	
}
